package com.shuwen.gcdj.service.report;

import com.alibaba.excel.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shuwen.gcdj.bean.conditionMonitoring.response.HealthResp;
import com.shuwen.gcdj.bean.conditionMonitoring.response.StatisticsTrendstabilityResp;
import com.shuwen.gcdj.bean.equipmentMaintenance.request.EquipmentMaintainReportReq;
import com.shuwen.gcdj.bean.equipmentMaintenance.request.EquipmentPeriodReq;
import com.shuwen.gcdj.bean.equipmentMaintenance.response.*;
import com.shuwen.gcdj.bean.sysDictionary.request.SysDictionaryReq;
import com.shuwen.gcdj.bean.sysDictionary.response.SysDictionaryResp;
import com.shuwen.gcdj.bean.workingConditions.request.StatisticConditionReq;
import com.shuwen.gcdj.bean.workingConditions.response.StatisticsEquipmentMechanismSensorsResp;
import com.shuwen.gcdj.bean.workingConditions.response.StatisticsWorkingconditionsResp;
import com.shuwen.gcdj.common.constant.Constants;
import com.shuwen.gcdj.entity.StrategyPlandetail;
import com.shuwen.gcdj.entity.basics.BasicsEquipment;
import com.shuwen.gcdj.mapper.mysql.PlanDetailMapper;
import com.shuwen.gcdj.mapper.mysql.Statistic.*;
import com.shuwen.gcdj.mapper.mysql.basics.BasicsEquipmentMapper;
import com.shuwen.gcdj.mapper.mysql.sysDictionary.SysDictionaryMapper;
import com.shuwen.gcdj.service.statistic.WorkingConditionsService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.*;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author XYC
 */
@Service
@Slf4j
@AllArgsConstructor
public class EquipmentMaintenanceReportService {

    private final StatisticsWorkingconditionsMapper statisticsWorkingconditionsMapper;

    private final StatisticsEquipmentmechanismsensorsMapper statisticsEquipmentmechanismsensorsMapper;

    private final StatisticsHealthMapper statisticsHealthMapper;

    private final SysDictionaryMapper sysDictionaryMapper;

    private final StatisticsTrendstabilityMapper statisticsTrendstabilityMapper;

    private final BasicsEquipmentMapper basicsEquipmentMapper;

    private final EquipmentMainTainReportService equipmentMainTainReportService;

    private final PlanDetailMapper planDetailMappers;


    public EquipmentOpsTotalReportResp getEquipmentOpsTotalReport(EquipmentPeriodReq req) {
        RangeTimeResp periods = getTimeRange(req);
        EquipmentOpsTotalReportResp result = new EquipmentOpsTotalReportResp();
        List<String> equipmentCodes = Arrays.asList(req.getEquipmentCode().split(","));
        result.setEquipmentInstitutionsModels(getEquipmentInstitutions(req));
        result.setEquipmentHealthAssessmentModels(getEquipmentHealthAssessment(req));
        result.setEquipmentTrendSmoothModels(getEquipmentTrendSmooth(req));
        EquipmentMaintainReportReq report = new EquipmentMaintainReportReq();
        report.setEquipmentCodes(equipmentCodes);
        report.setStartDate(periods.getStartTime());
        report.setEndDate(periods.getEndTime());
        result.setWorkOrderStatisticsModels(equipmentMainTainReportService.getWorkOrderStatisticsData(report));
        result.setSecondTotal(getPlanStatisticsData(report).stream().findFirst().orElse(new EquipmentPlanResp()).getSecondTotal());
        return result;
    }


    //设备运行机构
    public List<EquipmentInstitutionsResp> getEquipmentInstitutions(EquipmentPeriodReq req) {
        List<EquipmentInstitutionsResp> equipmentInstitutionsResps = new ArrayList<>();
        RangeTimeResp getTimeRange = getTimeRange(req);
        StatisticConditionReq statisticConditionReq = new StatisticConditionReq();
        statisticConditionReq.setEquipmentCode(req.getEquipmentCode());
        EquipmentPeriodReq periodReq = new EquipmentPeriodReq();
        periodReq.setStartTime(getTimeRange.getStartTime());
        periodReq.setEndTime(getTimeRange.getEndTime());
        periodReq.setEquipmentCode(req.getEquipmentCode());
        //工况统计
        List<StatisticsWorkingconditionsResp> statistic = statisticsWorkingconditionsMapper.getStatistic(periodReq);
        //设备机构
        List<StatisticsEquipmentMechanismSensorsResp> institutionData = statisticsEquipmentmechanismsensorsMapper.getResult(statisticConditionReq);
        List<LocalDate> times = statistic.stream().map(statisticsWorkingconditionsResp -> statisticsWorkingconditionsResp.getTime().toLocalDate()).distinct().collect(Collectors.toList());

        //查询带载每日运行时长
        for (StatisticsEquipmentMechanismSensorsResp resp : institutionData) {
            double duration = 0;
            EquipmentInstitutionsResp institutions = new EquipmentInstitutionsResp();
            for (LocalDate dateTime : times) {
                ///运载当日最新一条数据
                StatisticsWorkingconditionsResp statisticsWorkingconditionsResp = statistic.stream()
                        .filter(workingconditionsResp -> workingconditionsResp.getIsloaded().equals(true)
                                && workingconditionsResp.getTime().toLocalDate().equals(dateTime)
                                && workingconditionsResp.getInstitution().equals(resp.getInstitution()))
                        .max(Comparator.comparing(StatisticsWorkingconditionsResp::getTime))
                        .orElse(new StatisticsWorkingconditionsResp());
                duration +=statisticsWorkingconditionsResp.getDuration() != null ? statisticsWorkingconditionsResp.getDuration() : 0;
            }
            institutions.setInstitutionsName(resp.getInstitution());
            institutions.setLogotype(resp.getLogotype());
            institutions.setRuntimeDuration(Double.toString(duration));
            institutions.setPercentage(String.format("%.2f", (duration / getTimeRange.getHoursCount()) * 100));
            equipmentInstitutionsResps.add(institutions);
        }
        return equipmentInstitutionsResps;
    }


    //设备健康评估
    public List<EquipmentHealthAssessmentResp> getEquipmentHealthAssessment(EquipmentPeriodReq req) {
        List<EquipmentHealthAssessmentResp> equipmentHealthAssessmentResps = new ArrayList<>();
        //本期
        RangeTimeResp getTimeRange = getTimeRange(req);
        EquipmentPeriodReq periodReq = new EquipmentPeriodReq();
        periodReq.setStartTime(getTimeRange.getStartTime());
        periodReq.setEndTime(getTimeRange.getEndTime());
        periodReq.setEquipmentCode(req.getEquipmentCode());
        //本期数据
        List<HealthResp> healthResps = statisticsHealthMapper.getMaintenancer(periodReq);
        ///本周期日期
        List<LocalDate> time = healthResps.stream().map(healthResp -> healthResp.getTime().toLocalDate()).distinct().collect(Collectors.toList());
        //上期
        EquipmentPeriodReq equipmentPeriodReq = new EquipmentPeriodReq();
        BeanUtils.copyProperties(req, equipmentPeriodReq);
        equipmentPeriodReq.setLastPeriod(req.getPeriod());
        RangeTimeResp lastPeriod = getTimeRange(equipmentPeriodReq);
        EquipmentPeriodReq equipmentPeriod = new EquipmentPeriodReq();
        equipmentPeriod.setStartTime(lastPeriod.getStartTime());
        equipmentPeriod.setEndTime(lastPeriod.getEndTime());
        equipmentPeriod.setEquipmentCode(req.getEquipmentCode());
        //设备健康度(上周期)
        List<HealthResp> lastPerioddata = statisticsHealthMapper.getMaintenancer(equipmentPeriod);
        ///上周期日期
        List<LocalDate> lastPeriodDate = lastPerioddata.stream().map(x -> x.getTime().toLocalDate()).distinct().collect(Collectors.toList());

        List<HealthResp> dataAll = healthResps;
        dataAll.addAll(lastPerioddata);
        List<String> evaluateobject = dataAll.stream().filter(healthResp -> !healthResp.getLocation().equals(Constants.HEALTH_BEARINGS_VALUE))
                .map(HealthResp::getEvaluateObject).distinct().collect(Collectors.toList());

        for (String evaluate : evaluateobject.stream().distinct().collect(Collectors.toList())) {
            EquipmentHealthAssessmentResp resp = new EquipmentHealthAssessmentResp();
            //获取本期统计数据
            double duration=dataForThisPeriod(healthResps, time, evaluate);
            //获取上期统计数据
            double lastDuration =dataForThisPeriod(lastPerioddata, lastPeriodDate, evaluate);
            String thisTimeData = String.format("%.2f", duration / getTimeRange.getDayCount());
            String lastData = String.format("%.2f", lastDuration / lastPeriod.getDayCount());
            double range = Double.parseDouble(thisTimeData);
            String increase = thisTimeData + "-" + lastData;
            resp.setInstitutionsName(evaluate);
            resp.setHealth(thisTimeData);
            resp.setDuration(lastData);
            resp.setLogotype(Objects.equals(evaluate, Constants.MACHINE) ? Constants.LOGOTYPE_ONE : evaluate.contains(Constants.REEL) ? Constants.LOGOTYPE_TWO : Constants.LOGOTYPE_THREE);
            resp.setIncrease(BigDecimal.valueOf(WorkingConditionsService.eval(increase)).toString());
            resp.setJudgment(range <= Constants.ANOMALY_THRESHOLD ? Constants.ABNORMAL : (range <= Constants.ALERT_THRESHOLD && range > Constants.ANOMALY_THRESHOLD) ? Constants.EARLY_WARNING : Constants.NORMAL);
            equipmentHealthAssessmentResps.add(resp);
        }
        return equipmentHealthAssessmentResps;
    }

    private double dataForThisPeriod(List<HealthResp> healthResps, List<LocalDate> time, String evaluate) {
        double duration = 0;
        for (LocalDate localDate : time) {
            HealthResp latestData = healthResps.stream().filter(healthResp -> healthResp.getEvaluateObject().equals(evaluate) && healthResp.getTime().toLocalDate().equals(localDate))
                    .max(Comparator.comparing(HealthResp::getTime)).orElse(new HealthResp());
            duration += latestData.getStatusValue() != null ? latestData.getStatusValue() : 0;
        }
        return duration;
    }

    //故障分析
    public List<EquipmentTrendSmoothResp> getEquipmentTrendSmooth(EquipmentPeriodReq req) {

        List<EquipmentTrendSmoothResp> equipmentTrendSmoothResps = new ArrayList<>();
        SysDictionaryReq dictionaryReq = new SysDictionaryReq();

        //获取状态中心趋势平稳度位置
        dictionaryReq.setParentCode(Constants.STATISTICS_TRENDSTABILITY_MONITOR_LOCATION);
        dictionaryReq.setOperateObject(req.getEquipmentCode());
        List<SysDictionaryResp> trendSmoothing = sysDictionaryMapper.getList(dictionaryReq);
        //本期
        RangeTimeResp getTimeRange = getTimeRange(req);
        EquipmentPeriodReq periodReq = new EquipmentPeriodReq();
        periodReq.setStartTime(getTimeRange.getStartTime());
        periodReq.setEndTime(getTimeRange.getEndTime());
        periodReq.setEquipmentCode(req.getEquipmentCode());
        List<StatisticsTrendstabilityResp> statistic = statisticsTrendstabilityMapper.getStatistic(periodReq);
        statistic = statistic.stream().filter(trendstabilityResp -> !trendstabilityResp.getEvaluateObject().contains(Constants.JIANG_KANG)).collect(Collectors.toList());
        ///本周期日期
        List<LocalDate> localDates = statistic.stream().map(x -> x.getTime().toLocalDate()).distinct().collect(Collectors.toList());
        //上期
        EquipmentPeriodReq period = new EquipmentPeriodReq();
        BeanUtils.copyProperties(req, period);
        period.setLastPeriod(req.getPeriod());
        RangeTimeResp lastPeriod = getTimeRange(period);
        EquipmentPeriodReq equipmentPeriodReq = new EquipmentPeriodReq();
        equipmentPeriodReq.setStartTime(lastPeriod.getStartTime());
        equipmentPeriodReq.setEndTime(lastPeriod.getEndTime());
        equipmentPeriodReq.setEquipmentCode(req.getEquipmentCode());
        //设备趋势平稳度(上期)
        List<StatisticsTrendstabilityResp> lastTrenddata = statisticsTrendstabilityMapper.getStatistic(equipmentPeriodReq);
        lastTrenddata = lastTrenddata.stream().filter(trendstabilityResp -> !trendstabilityResp.getEvaluateObject().contains(Constants.JIANG_KANG)).collect(Collectors.toList());
        ///上期时间
        List<LocalDate> localDateList = lastTrenddata.stream().map(trendstabilityResp -> trendstabilityResp.getTime().toLocalDate()).distinct().collect(Collectors.toList());
        //取出1起升2起升3起升
        //List<String> trendSmoothingValue = trendSmoothing.stream().filter(dictionaryResp -> !Objects.equals(dictionaryResp.getRemark(), "MainBeam"))
        //.map(SysDictionaryResp::getRemark).collect(Collectors.toList());
        for (SysDictionaryResp sysDictionaryResp : trendSmoothing) {
            List<EquipmentTrendResp> equipmentTrendData = new ArrayList<>();
            EquipmentTrendSmoothResp smooth = new EquipmentTrendSmoothResp();
            List<StatisticsTrendstabilityResp> trendData = statistic.stream().filter(trendstabilityResp -> trendstabilityResp.getMonitorLocation().equals(sysDictionaryResp.getValue())).collect(Collectors.toList());
            List<String> evaluateObjectes = trendData.stream().map(StatisticsTrendstabilityResp::getEvaluateObject).distinct().collect(Collectors.toList());
            for (String evaluate : evaluateObjectes) {
                EquipmentTrendResp resp = new EquipmentTrendResp();
                //本周期平稳度
                double duration = 0;
                ///上周期平稳度
                double lastDuration = 0;
                duration = getDuration(statistic, localDates, sysDictionaryResp, evaluate, duration);
                lastDuration = getDuration(lastTrenddata, localDateList, sysDictionaryResp, evaluate, lastDuration);
                String thisTimeData = String.format("%.2f", duration / (double) getTimeRange.getDayCount());
                String lastData = String.format("%.2f", lastDuration / lastPeriod.getDayCount());
                double range = Double.parseDouble(thisTimeData);
                String increase = thisTimeData + "-" + lastData;
                resp.setEvaluateObject(evaluate);
                resp.setTrendSmoothness(thisTimeData);
                resp.setDuration(lastData);
                resp.setIncrease(String.format("%.2f", WorkingConditionsService.eval(increase)));
                resp.setJudgment(range <= Constants.ANOMALY_THRESHOLD ? Constants.ABNORMAL : (range <= Constants.ALERT_THRESHOLD && range > Constants.ANOMALY_THRESHOLD) ? Constants.EARLY_WARNING : Constants.NORMAL);
                equipmentTrendData.add(resp);
            }
            smooth.setEqupimentCode(req.getEquipmentCode());
            smooth.setEvaluateObject(sysDictionaryResp.getName());
            smooth.setLogotype(sysDictionaryResp.getRemark().contains(Constants.LIFTING) ? Constants.LOGOTYPE_ONE :sysDictionaryResp.getRemark().contains(Constants.MAIN_BEAM)? Constants.LOGOTYPE_TWO: Constants.LOGOTYPE_THREE);
            smooth.setEquipmentTrendDatas(equipmentTrendData);
            equipmentTrendSmoothResps.add(smooth);
        }
        return equipmentTrendSmoothResps;
    }

    private double getDuration(List<StatisticsTrendstabilityResp> data, List<LocalDate> localDates, SysDictionaryResp sysDictionaryResp, String evaluate, double duration) {
        for (LocalDate dateTime : localDates) {
            StatisticsTrendstabilityResp trendstabilityResp = data.stream().filter(statisticsTrendstabilityResp -> statisticsTrendstabilityResp.getTime().toLocalDate().equals(dateTime)
                            && statisticsTrendstabilityResp.getEvaluateObject().equals(evaluate) && statisticsTrendstabilityResp.getMonitorLocation().equals(sysDictionaryResp.getValue()))
                    .max(Comparator.comparing(StatisticsTrendstabilityResp::getTime)).orElse(new StatisticsTrendstabilityResp());
            duration += trendstabilityResp.getStatusValue() != null ? trendstabilityResp.getStatusValue() : 0;
        }
        return duration;
    }

    public List<EquipmentPlanResp> getPlanStatisticsData(EquipmentMaintainReportReq req) {
        List<EquipmentPlanResp> result = new ArrayList();
        List<BasicsEquipment> basicsEquipments = basicsEquipmentMapper.selectList(new QueryWrapper<BasicsEquipment>().lambda());
        basicsEquipments = basicsEquipments.stream().filter(basicsEquipment -> req.getEquipmentCodes().contains(basicsEquipment.getCode())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(basicsEquipments)) {
            return result;
        }
        //List<String> codes = basicsEquipments.stream().map(BasicsEquipment::getCode).collect(Collectors.toList());
        List<String> Equipmentids = basicsEquipments.stream().map(BasicsEquipment::getId).collect(Collectors.toList());
        //计划
        List<StrategyPlandetail> planDetail = planDetailMappers.getStatistic(req, Equipmentids);
        planDetail = planDetail.stream().filter(plandetail -> plandetail.getMaintenanceType().equals(2)).collect(Collectors.toList());
        for (BasicsEquipment equals : basicsEquipments) {
            EquipmentPlanResp data = new EquipmentPlanResp();
            int count = Math.toIntExact(planDetail.stream().filter(strategyPlandetail -> strategyPlandetail.getEquipmentId().equals(equals.getId())).count());
            data.setName(equals.getName());
            data.setCode(equals.getCode());
            data.setSecondTotal(Integer.toString(count));
            result.add(data);
        }
        return result;
    }


    public RangeTimeResp getTimeRange(EquipmentPeriodReq req) {
        RangeTimeResp rangeTimeResp = new RangeTimeResp();
        LocalDateTime dateTime = req.getStartTime() == null ? LocalDateTime.now() : req.getStartTime();
        if (req.getLastPeriod() != null) {
            switch (req.getLastPeriod().toString()) {
                case Constants.PERIOD_TYPE_DAY:
                    dateTime = dateTime.minusDays(-1);
                    break;
                case Constants.PERIOD_TYPE_WEEK:
                    dateTime = dateTime.minusDays(7).minusMinutes(1);
                    break;
                case Constants.PERIOD_TYPE_MONTH:
                    dateTime = dateTime.minusMonths(1);
                    break;
            }
        }
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = dateTime.atZone(zoneId);
        Date date = Date.from(zdt.toInstant());
        Calendar aCalendar = Calendar.getInstance();
        aCalendar.setTime(date);
        //本月天数
        int days = aCalendar.getActualMaximum(Calendar.DATE);
        switch (req.getPeriod().toString()) {

            case Constants.PERIOD_TYPE_DAY:
                //天
                rangeTimeResp.setStartTime(dateTime.toLocalDate().atStartOfDay());
                rangeTimeResp.setEndTime(LocalDateTime.of(dateTime.toLocalDate(), LocalTime.MAX));
                rangeTimeResp.setHoursCount(24);
                rangeTimeResp.setDayCount(1);
                break;
            case Constants.PERIOD_TYPE_WEEK:
                //周
                rangeTimeResp.setStartTime(dateTime.toLocalDate().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).atStartOfDay());
                rangeTimeResp.setEndTime(LocalDateTime.of(dateTime.toLocalDate().with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)), LocalTime.MAX));
                rangeTimeResp.setHoursCount(7 * 24);
                rangeTimeResp.setDayCount(7);
                break;
            case Constants.PERIOD_TYPE_MONTH:
                //月
                rangeTimeResp.setStartTime(dateTime.toLocalDate().with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay());
                rangeTimeResp.setEndTime(LocalDateTime.of(dateTime.toLocalDate().with(TemporalAdjusters.lastDayOfMonth()), LocalTime.MAX));
                rangeTimeResp.setHoursCount(days * 24);
                rangeTimeResp.setDayCount(days);
                break;
        }
        return rangeTimeResp;
    }
}

